# -*- coding: utf8 -*-

"""内存共享
"""

import os
import mmap
import json
import cPickle as pickle
import logging
logger = logging.getLogger('bt_server')

from base.settings import SHARE_MEM_ID, SHARE_MEM_SIZE

class ShareMem(object):

    # 只能读，如果执行写操作，raises a TypeError exception
    SHARE_MEM_ACCESS_WRITE = mmap.ACCESS_WRITE
    # 可读可写
    SHARE_MEM_ACCESS_READ = mmap.ACCESS_READ
    # 可读可写，但不更新到文件中去
    SHARE_MEM_ACCESS_COPY = mmap.ACCESS_COPY

    def __init__(self, access=SHARE_MEM_ACCESS_WRITE, tagname=SHARE_MEM_ID, length=SHARE_MEM_SIZE):
        self._fileno = os.open(SHARE_MEM_ID, os.O_RDWR | os.O_CREAT)
        self._length = length
        self._access = access
        self._tagname = tagname

        if not os.fstat(self._fileno).st_size == self._length:
            os.ftruncate(self._fileno, self._length)
        self._mm = mmap.mmap(fileno=self._fileno, length=self._length, flags=mmap.MAP_SHARED, access=self._access)

    def write(self, data, length):
        try:
            self._mm.seek(0)
            content = str(length) + ':' + data
            self._mm.write(content)
            content_begin = len(str(length)) + 1
            content_end = self._mm.tell()
            content_length = content_end - content_begin
        except Exception as e:
            logger.error(e)
            raise

    def read(self):
        try:
            self._mm.seek(0)
            index = self._mm.find(':')
            if index == -1:
                return None
            head = self._mm.read(index + 1)
            data_length = int(head[:-1])
            data = self._mm.read(data_length)
            return data
        except Exception as e:
            logger.error(e)
            raise

    def json_write(self, obj):
        try:
            data = json.dumps(obj)
            length = len(data)
            self.write(data, length)
        except Exception as e:
            logger.error(e)
            raise

    def json_read(self):
        try:
            data = self.read()
            obj = json.loads(data)
            return obj
        except Exception as e:
            logger.error(e)
            raise

    def pickle_write(self, obj):
        try:
            data = pickle.dumps(obj)
            length = len(data)
            self.write(data, length)
        except Exception as e:
            logger.error(e)
            raise

    def pickle_read(self):
        try:
            data = self.read()
            obj = pickle.loads(data)
            return obj
        except Exception as e:
            logger.error(e)
            raise

    def close(self):
        self._mm.close()
        os.close(self._fileno)
